#include "game.h"
#include "loc/loc-consts.h"
#include "loc/rva.h"
#include "msg.h"
#include <cassert>
#include <intrin.h>
#include <ranges>

using namespace std;

unordered_map<uint32, string> Game::spell_names_{};
unordered_map<uint32, uint64> Game::item_type_arr_map_{};

// FIXME: enable 获取有问题, 非潜行时应该是1, 但是现在都是返回 0
std::tuple<uint32, uint32, uint8> Game::get_spell_cooldown(uint32 spell_id) {
  try {
    if (spell_id == 0) {
      return make_tuple(0, 0, 0);
    }
    uint64 rcx = spell_id;
    uint64 rdx = 0;
    uint64 r9_param[7] = {0};
    uint64 r8 = ((uint64)r9_param) + 4;
    uint64 r9 = (uint64)r9_param;
    *(uint32 *)(r9 + 8) = 0x3F800000;
    uint64 addr = base_ + RVA_SPELL_COOLDOWN_CALL;
    // 构造 args
    uint64 args[10] = {addr, rcx, rdx, r8, r9};
    send_call(args);
    uint32 startTime = r4(r9);
    uint32 duration = r4(r8);
    uint8 enabled = r1(r9 + 0x30);
    return std::tuple<uint32, uint32, uint8>(startTime, duration, enabled);
  } catch (...) {
    dbgprintu8("codergege [%s][%03d]\n", __FUNCTION__, __LINE__);
  }
  return make_tuple(0, 0, 0);
}

std::string Game::get_spell_name_ex(uint32 spell_id) {
  uint64 addr{base_ + RVA_SPELL_NAME_CALL};
  uint64 rcx{base_ + RVA_SPELL_NAME_BASE};
  uint64 rdx{spell_id};
  uint64 r8{0};
  uint64 r9[1];
  uint64 args[10]{addr, rcx, rdx, r8, (uint64)r9};
  uint64 rax = send_call(args);
  if (rax > 0) {
    return (char *)(rax + r4(rax));
  }
  return "未知法术名称";
}

// FIXME: 有bug, 先用 ex 版本
std::string Game::get_spell_name(uint32 spell_id) {
  auto it = spell_names_.find(spell_id);
  if (it != spell_names_.end()) {
    return it->second;
  }
  // registers
  uint64 rax{0}, rbx{0}, rcx{base_ + RVA_SPELL_NAME_BASE}, rdx{spell_id},
      rsi{0}, rdi{0}, r8v{0}, r9{0}, r10{0}, r11{0}, r12{0}, r13{0}, r14{0},
      r15{0};
  rax = r8(rcx + 8);
  rdi = (uint32)rdx;
  if (rdi < r4(rcx + 0x1D0) || rdx > r4(rcx + 0x1CC)) {
    dbgprintu8("codergege [%s][%03d] \n", __FUNCTION__, __LINE__);
    return "未知法术";
  }
  rcx = r8(rcx + 0x140);
  rdx = (uint32)rdi;
  // sub call
  r10 = (uint32)rdx;
  r8v = rcx;
  rax = r4(rcx + 0x40);
  uint32 min = r4(rcx + 0x40);
  uint32 max = r4(rcx + 0x44);
  if ((uint32)r10 < min || (uint32)r10 > max) {
    dbgprintu8("codergege [%s][%03d] \n", __FUNCTION__, __LINE__);
    return "未知法术";
  }
  uint64 index_arr = r8(rcx + 0x80);
  uint64 index_arr_size = r8(rcx + 0x88);
  uint32 target = spell_id - min;
  for (auto i : views::iota(0u, index_arr_size)) {
    if (r4(index_arr + i * 8) == target) {
      auto index = r4(index_arr + i * 8 + 4);
      index *= r4(r8v + 0x38);
      rax = r8(r8v + 8) + index;
      if (rax > 0) {
        auto name = (char *)(rax + r4(rax));
        spell_names_.insert({spell_id, name});
        return name;
      } else {
        dbgprintu8("codergege [%s][%03d] \n", __FUNCTION__, __LINE__);
        auto name = "未知法术";
        spell_names_.insert({spell_id, name});
        return name;
      }
    }
  }

  dbgprintu8("codergege [%s][%03d] \n", __FUNCTION__, __LINE__);
  auto name = "未知法术";
  spell_names_.insert({spell_id, name});
  return name;
}

std::string Game::get_item_subtype(uint32 type_index, uint32 subtype_index) {
  uint64 call_addr{base_ + RVA_ITEM_SUBTYPE_CALL};
  uint64 rcx{type_index};
  uint64 rdx{subtype_index};
  uint64 r8{0};
  uint64 r9{0};
  uint64 args[10]{call_addr, rcx, rdx, r8, r9};
  auto ret = send_call(args);
  if (ret > 0) {
    auto offset = r4(ret);
    return (char *)(ret + offset);
  }

  return "未知子类";
}

uint32 Game::get_item_subtype_index(uint32 item_id, uint32 edxv,
                                    uint32 r8dv) const {
  // 参数
  uint64 rcx = get_item_type_arr(item_id);
  uint64 r9 = base_ + RVA_ITEM_TYPE_ARR_BASE;
  // 用到的 registers
  uint64 rax{0}, rbx{0}, rdx{edxv}, r8v{r8dv}, r10{0}, r11{0}, rsi{0}, rdi{0};
  // mov rbx,r9
  rbx = r9;
  // mov r11,rcx
  r11 = rcx;
  // mov r9d,edx
  r9 = (uint32)rdx;
  // mov rdx,rcx
  rdx = rcx;
  // sub rdx,r8
  rdx -= r8v;
  // mov r10,qword ptr ds:[rbx+140]
  r10 = r8(rbx + 0x140);
  // test r10,r10
  // je wowclassic.7FF7530F6215
  if (r10 > 0) {
    // mov r8d,dword ptr ds:[r10+48]
    r8v = r4(r10 + 0x48);
    // mov rax,rdx
    rax = rdx;
    // imul r8d,dword ptr ds:[r10+38]
    r8v = (uint32)r8v * r4(r10 + 0x38);
    // sub rax,qword ptr ds:[r10+8]
    rax -= r8(r10 + 8);
    // cmp rax,r8
    // jae wowclassic.7FF7530F6215
    if (rax < r8v) {
      // mov qword ptr ss:[rsp+58],rsi
      // mov qword ptr ss:[rsp+60],rdi
      // mov rdi,qword ptr ds:[rbx+10]
      rdi = r8(rbx + 0x10);
      // movsxd rsi,r9d
      rsi = (uint32)r9;
      // lea rax,qword ptr ds:[rsi+rsi*2]
      rax = rsi * 3;
      // lea r8,qword ptr ds:[rax*8]
      r8v = rax * 8;
      // add rdi,r8
      rdi += r8v;
      // mov ecx,dword ptr ds:[rdi+8]
      rcx = r4(rdi + 8);
      switch (rcx) {
      case 1: {
        rcx -= 1;
      } break;
      case 2: {
        rcx -= 2;
      } break;
      case 3: {
        rcx -= 3;
        // mov edx,dword ptr ds:[rdi+C]
        rdx = r4(rdi + 0xC);
        // mov r9d,40
        r9 = 0x40;
        // sub r9d,dword ptr ds:[rdi+10]
        r9 -= r4(rdi + 0x10);
        // mov eax,edx
        rax = (uint32)rdx;
        // mov rsi,qword ptr ss:[rsp+58]
        // and eax,7
        rax = (uint32)rax & 7;
        // mov rdi,qword ptr ss:[rsp+60]
        // mov ecx,r9d
        rcx = (uint32)r9;
        // sub ecx,eax
        rcx -= (uint32)rax;
        // mov eax,edx
        rax = (uint32)rdx;
        // shr rax,3
        rax >>= 3;
        // mov rdx,qword ptr ds:[rax+r11]
        rdx = r8(rax + r11);
        // mov rax,qword ptr ds:[rbx+28]
        rax = r8(rbx + 0x28);
        // shl rdx,cl
        rdx <<= (uint8)rcx;
        // mov ecx,r9d
        rcx = (uint32)r9;
        // shr rdx,cl
        rdx >>= (uint8)rcx;
        // mov ecx,edx
        rcx = (uint32)rdx;
        // mov rax,qword ptr ds:[rax+r8]
        rax = r8(rax + r8v);
        // movzx eax,byte ptr ds:[rax+rcx*4]
        rax = r1(rax + rcx * 4);
        return (uint32)rax;
      } break;
      case 5: {
        rcx -= 3;
      } break;
      default:
        break;
      }
      return 0;
    }
  }
  rax = r8(rbx + 8);
  rax = r8(rax + 0x20);
  rax = (uint32)r8(rax + r9 * 4);
  rax = (uint32)r8(rax + rdx);
  return rax;
}

string Game::get_item_type(uint32 index, uint32 r8d) const {
  // registers
  uint64 rax{0}, rbx{0}, rcx{0}, rdx{index}, r8v{r8d}, r9{0}, r10{0}, r11{0},
      rsi{0}, rdi{0};
  // 参数
  rcx = base_ + RVA_ITEM_TYPE_NAME_BASE;
  rax = r8(rcx + 8); // base1 = [base+8]
  r9 = (uint32)rdx;
  if (r8(rax + 0x6C) != 0) {
    rax = (uint32)r8v;
    r8v = rax * 3;
    rax = r8(rcx + 0x148); // base2 = [base+148]
    r10 = r8(rax + r8v * 8);
    r11 = rax + r8v * 8; // base3 = base2+0x18*r8d
    rbx = r8(r11 + 8);   // base4 = [base3 + 8]
    r8v = (uint32)0;
    rax = (uint8)r9; // index
    rax = ((uint32)rax) ^ 0x811C9DC5;
    rcx = ((uint32)rax) * 0x1000193;
    rdi = r10 - 1;
    rax = (uint32)rdx; // index
    rax = ((uint32)rax) >> 8;
    rax = (uint8)rax;
    rcx = ((uint32)rcx) ^ ((uint32)rax);
    rax = (uint32)r9;
    rax = ((uint32)rax) >> 0x10;
    rdx = (uint32)(((uint32)rcx) * 0x1000193);
    rax = (uint8)rax;
    rdx = (uint32)(((uint32)rdx) ^ ((uint32)rax));
    rax = (uint32)r9;
    rax = (uint32)(((uint32)rax) >> 0x18);
    rcx = (uint32)((uint32)rdx * 0x1000193);
    rcx = (uint32)(((uint32)rcx) ^ ((uint32)rax));
    rcx = (uint32)((uint32)rcx * 0x1000193);
    rcx = rcx & rdi;
    rax = rcx;
    rax = rax << 4;
    rax += rbx; // base4 + offset
    rdx = r4(rax);
    if ((uint32)rdx == 0x80000001)
      // return 0;
      return "未知分类";
    r11 = r8(r11 + 0x18);
    do {
      if (r11 != 0) {
        if ((uint32)rdx != 0x80000000) {
          if ((uint32)rdx == (uint32)r9) {
            break;
          }
        }
      } else {
        if ((uint32)rdx == (uint32)r9) {
          break;
        }
      }
      r8v++;
      rcx += r8v;
      rcx = rcx & rdi;
      rax = rcx;
      rax = rax << 4;
      rax += rbx;
      rdx = r4(rax);
      if ((uint32)rdx == 0x80000001)
        // return 0;
        return "未知分类";
    } while (true);
    if ((uint32)rdx == (uint32)r9) {
      r10 = r10 << 4;
      r10 += rbx;
      if (rax == r10) {
        // return 0;
        return "未知分类";
      }
      // return r8(rax + 8);

      rax = r8(rax + 8);
      if (rax > 0) {
        uint64 rcx = r4(rax);
        if (rcx > 0) {
          return (char *)(rax + rcx);
        }
      }
      return "未知分类";
    }
  }
  // return 0;
  return "未知分类";
}

uint32 Game::get_item_type_index(uint32 item_id, uint32 edxv,
                                 uint32 r8dv) const {
  // 参数
  uint64 rcx = get_item_type_arr(item_id);
  uint64 r9 = base_ + RVA_ITEM_TYPE_ARR_BASE;
  // 用到的 registers
  uint64 rax{0}, rbx{0}, rdx{0}, r11{0}, r10{0}, r8v{0}, rsi{0}, rdi{0};
  rbx = r9;  // base
  r11 = rcx; // type_arr
  r9 = edxv;
  rdx = rcx;
  rdx -= r8dv;           // type_arr - r8dv
  r10 = r8(rbx + 0x140); // base1
  if (r10 != 0) {
    r8v = r4(r10 + 0x48);                 // r8d
    rax = rdx;                            // type_arr - r8dv
    r8v = ((uint32)r8v) * r4(r10 + 0x38); // r8d
    rax -= r8(r10 + 8);
    if (rax < r8v) {
      rdi = r8(rbx + 0x10); // base2=[base+10]
      rsi = (uint32)r9;
      rax = 3 * rsi;
      r8v = 8 * rax;
      rdi += r8v; // base2+18*edxv
      rcx = r4(rdi + 8);
      // switch case
      switch (rcx) {
      case 1: {
        rcx -= 1;
        rdx = (uint32)r4(rdi + 0xC);
        r9 = (uint32)0x40;
        r9 -= r4(rdi + 0x10);
        rax = (uint32)rdx;
        rax = (uint32)(((uint32)rax) & 7);
        rcx = (uint32)r9;
        rcx -= (uint32)rax;
        rax = (uint32)rdx;
        rax = rax >> 3;
        rax = r8(rax + r11);
        rax = rax << (uint8)rcx;
        rcx = (uint32)r9;
        rax = rax >> (uint8)rcx;
        return rax;
      } break;
      case 2: {
        rcx -= 2;
        // TODO:
        // 00007FF69A44E054  | 48:8BCB               | mov rcx,rbx |
        // 00007FF69A44E057  | E8 B4472900           | call
        // wowclassic.7FF69A6E2810            | 00007FF69A44E05C  | 48:8B4B 58
        // | mov rcx,qword ptr ds:[rbx+58]           | 00007FF69A44E060  |
        // 48:8D14B6             | lea rdx,qword ptr ds:[rsi+rsi*4]        |
        // 00007FF69A44E064  | 4C:8D4424 50          | lea r8,qword ptr
        // ss:[rsp+50]            | 00007FF69A44E069  | 894424 50             |
        // mov dword ptr ss:[rsp+50],eax           | 00007FF69A44E06D  |
        // 48:8D1CD1             | lea rbx,qword ptr ds:[rcx+rdx*8]        |
        // 00007FF69A44E071  | 48:8BCB               | mov rcx,rbx |
        // 00007FF69A44E074  | 48:8D5424 20          | lea rdx,qword ptr
        // ss:[rsp+20]           | 00007FF69A44E079  | E8 42F6FFFF           |
        // call wowclassic.7FF69A44D6C0            | 00007FF69A44E07E  | 48:8B13
        // | mov rdx,qword ptr ds:[rbx]              | 00007FF69A44E081  |
        // 48:8B4B 08            | mov rcx,qword ptr ds:[rbx+8]            |
        // 00007FF69A44E085  | 48:8B4424 28          | mov rax,qword ptr
        // ss:[rsp+28]           | [rsp+28]:Tcpip6_WSHOpenSocket+205E0
        // 00007FF69A44E08A  | 4C:8D04D1             | lea r8,qword ptr
        // ds:[rcx+rdx*8]         | 00007FF69A44E08E  | 49:3BC0               |
        // cmp rax,r8                              | 00007FF69A44E091  | 75 13
        // | jne wowclassic.7FF69A44E0A6             | 00007FF69A44E093  | 8B47
        // 0C               | mov eax,dword ptr ds:[rdi+C]            |
        // 00007FF69A44E096  | 48:8B7C24 60          | mov rdi,qword ptr
        // ss:[rsp+60]           | [rsp+60]:BaseThreadInitThunk+14
        // 00007FF69A44E09B  | 48:8B7424 58          | mov rsi,qword ptr
        // ss:[rsp+58]           | 00007FF69A44E0A0  | 48:83C4 40            |
        // add rsp,40                              | 00007FF69A44E0A4  | 5B |
        // pop rbx                                 | 00007FF69A44E0A5  | C3 |
        // ret                                     | 00007FF69A44E0A6  | 8B40 04
        // | mov eax,dword ptr ds:[rax+4]            | 00007FF69A44E0A9  |
        // 48:8B7424 58          | mov rsi,qword ptr ss:[rsp+58]           |
        // 00007FF69A44E0AE  | 48:8B7C24 60          | mov rdi,qword ptr
        // ss:[rsp+60]           | [rsp+60]:BaseThreadInitThunk+14
        // 00007FF69A44E0B3  | 48:83C4 40            | add rsp,40 |
        // 00007FF69A44E0B7  | 5B                    | pop rbx |
        // 00007FF69A44E0B8  | C3                    | ret |
      } break;
      case 3: {
        rcx -= 3;
        rdx = r4(rdi + 0xC);
        r9 = (uint32)0x40;
        r9 -= r4(rdi + 0x10);
        rax = (uint32)rdx;
        rax = (uint32)(((uint32)rax) & 7);
        rcx = (uint32)r9;
        rcx -= (uint32)rax;
        rax = (uint32)rdx;
        rax = rax >> 3;
        rdx = r8(rax + r11);
        rax = r8(rbx + 0x28); // base+28
        rdx = rdx << (uint8)rcx;
        rcx = (uint32)r9;
        rdx = rdx >> (uint8)rcx;
        rcx = (uint32)rdx;
        rax = r8(rax + r8v);
        rax = r4(rax + rcx * 4);
        return rax;
      } break;
      case 5: {
        rax = (uint32)r4(rdi + 0x10);
        r9 = (uint32)0x40;
        rdx = (uint32)r4(rdi + 0xC);
        r9 = (uint32)r9 - (uint32)rax;
        r8v = (uint32)1;
        rcx = (uint32)(rax - 1);
        rax = (uint32)rdx;
        rax = (uint32)(((uint32)rax) & 7);
        r8v = (uint32)((uint32)r8v >> (uint8)rcx);
        rcx = (uint32)r9;
        rcx -= (uint32)rax;
        rax = (uint32)rdx;
        rax = rax >> 3;
        rax = r8(rax + r11);
        rax = rax << (uint8)rcx;
        rcx = (uint32)r9;
        rax = rax >> (uint8)rcx;
        rax = ((uint32)rax) ^ ((uint32)r8v);
        rax -= (uint32)r8v;
        return (uint32)rax;
      } break;
      default: {
        return 0;
      }
      }
    }
  }
  rax = r8(rbx + 8);
  rax = r8(rax + 0x20);
  rax = (uint32)r8(rax + r9 * 4);
  rax = (uint32)r8(rax + rdx);
  return rax;
}

uint64 Game::get_item_type_arr(uint32 item_id) const {
  auto it = item_type_arr_map_.find(item_id);
  if (it != item_type_arr_map_.end()) {
    return it->second;
  }
  auto base = base_ + RVA_ITEM_TYPE_ARR_BASE;
  auto item_id_min = r4(base + 0x1D0);
  auto item_id_max = r4(base + 0x1CC);
  if (item_id < item_id_min || item_id > item_id_max) {
    return 0;
  }
  auto tmp = r8(base + 0x140);
  auto arr = r8(tmp + 0x80);
  auto size = r8(tmp + 0x88);
  auto min = r4(tmp + 0x40);
  auto max = r4(tmp + 0x44);
  if (item_id < min || item_id > max) {
    return 0;
  }
  uint64 rax{0}, rbx{0}, rcx{tmp}, rdx{min}, r8v{0}, r9{0}, r10{item_id};
  // mov eax,r10d
  rax = (uint32)r10;
  // sub eax,edx
  rax -= (uint32)rdx;
  // mov edx,eax
  rdx = (uint32)rax;
  // mov rax,qword ptr ds:[rcx+80]
  rax = arr;
  // movzx r8d,word ptr ds:[rax+rdx*2]
  r8v = r2(rax + rdx * 2);
  // mov eax,FFFE
  rax = 0xFFFE;
  // cmp r8w,ax
  // je wowclassic.7FF7533A099B
  if ((uint16)r8v == (uint16)rax) {
    return 0;
  }
  // mov eax,FFFF
  rax = 0xFFFF;
  // cmp r8w,ax
  // je wowclassic.7FF7533A0939
  if ((uint16)r8v == (uint16)rax) {
    // TODO: 这里还有复杂分支, 暂时返回0
    return 0;
  }
  // movzx eax,word ptr ds:[rcx+48]
  rax = r2(rcx + 0x48);
  // cmp r8w,ax
  // jae wowclassic.7FF7533A0923
  if ((uint16)r8v >= (uint16)rax) {
    // TODO:
    // sub r8w,ax
    r8v -= (uint16)rax;
    // movzx eax,r8w
    rax = (uint16)r8v;
    // cmp eax,dword ptr ds:[rcx+54]
    // jae wowclassic.7FF7533A099B
    if ((uint32)rax >= r4(rcx + 0x54)) {
      return 0;
    }
    // imul eax,dword ptr ds:[rcx+3C]
    rax = ((uint32)rax) * (r4(rcx + 0x3C));
    // add rax,qword ptr ds:[rcx+10]
    rax += r8(rcx + 0x10);
    // ret
    item_type_arr_map_.insert({item_id, rax});
  }
  // mov eax,r8d
  rax = r8v;
  // imul eax,dword ptr ds:[rcx+38]
  rax = ((uint32)rax) * (r4(rcx + 0x38));
  // add rax,qword ptr ds:[rcx+8]
  // ret
  rax += r8(rcx + 8);
  item_type_arr_map_.insert({item_id, rax});
  return rax;
}

uint32 Game::get_time() { return r4(base_ + RVA_GET_TIME_BASE); }

void Game::key_down(uint32 code) {
  SendMessage(window_, WM_KEYDOWN, code, NULL);
}

void Game::key_up(uint32 code) { SendMessage(window_, WM_KEYUP, code, NULL); }

uint64 Game::get_object_index(uint64 id1, uint64 id2) {
  if (id1 == 0 || id2 == 0) {
    return 0;
  }
  uint64 index{0};
  uint64 base = r8(base_ + RVA_GET_OBJECT_INDEX_BASE); // base
  uint64 rcx = base + 0x40;                            // base1
  // in call
  uint64 rsi = rcx;
  uint64 rdi = 0;
  uint64 rax = 0;
  uint64 r10 = id2;
  uint64 rdx = 0xFF51AFD7ED558CCD;
  uint64 rbx = id1;
  uint64 r11 = 0xC4CEB9FE1A85EC53;
  uint64 r15 = r8(rsi);
  uint64 rbp = 0x400000000000000;
  uint64 r8v = rbx + r10;
  rax = r8v;
  rax = rax >> 0x21;
  rax = rax ^ r8v;
  rax = rax * rdx;
  uint64 r9 = rax;
  r9 = r9 >> 0x21;
  r9 = r9 ^ rax;
  rax = r8v + r10;
  rcx = rax;
  rcx = rcx >> 0x21;
  rcx = rcx ^ rax;
  rcx = rcx * rdx;
  r9 = r9 * r11;
  rdx = rcx;
  rdx = rdx >> 0x21;
  rdx = rdx ^ rcx;
  rdx = rdx * r11;
  rcx = r9;
  r11 = r15 - 1;
  rcx = rcx >> 0x21;
  rax = rdx;
  rax = rax >> 0x21;
  rcx = rcx ^ r9;
  r9 = r8(rsi + 8);
  rax = rax ^ rdx;
  rax += rcx;
  // 循环头
  while (true) {
    rax = rax & r11;
    rcx = 3 * rax;
    rdx = r8(r9 + rcx * 8);
    r8v = r9 + rcx * 8;
    if (rdx == 0 && r8(r8v + 8) == 0) {
      return 0;
    }
    if (rdx != 0 && r8(r8v + 8) != rbp && rbx == rdx && r8(r8v + 8) == r10) {
      break;
    }
    rdi++;
    rax += rdi;
  }
  index = r8(r8v + 0x10);
  return index;
}

uint64 Game::get_object(uint64 id1, uint64 id2) {
  if (id1 == 0 || id2 == 0) {
    return 0;
  }
  return get_object(get_object_index(id1, id2));
}

uint64 Game::get_object(uint64 index) {
  uint32 limit{0x3FFFFFFF};

  if ((index & limit) == 0) {
    return 0;
  }

  if (core_base_ == 0) {
    return 0;
  }

  auto core_tmp_index = r4(base_ + RVA_CORE_ARR_TMP_INDEX_BASE);

  uintptr core_arr = r8(core_base_ + core_tmp_index * 8);
  if (core_arr == 0) {
    return 0;
  }
  // 检查1
  if (r1(core_arr + get_object_check1) == 0) {
    return 0;
  }
  // 检查2
  if (r8(core_arr + get_object_check2) == 0) {
    return 0;
  }
  if (r4(r8(core_arr + get_object_check2)) != 0) {
    return 0;
  }

  uintptr middle_arr = r8(r8(core_arr + get_object_check2) + 8);
  // TODO: middle_arr size = r4(r8(core_arr + get_object_check2) + 10)
  // tmp = middle_arr + i*8
  // obj = r8(r8(tmp)+28)
  // 判断一下 obj 0
  auto shift_index = index & limit;
  uintptr p1 = r8(middle_arr + shift_index * 8);
  if (r8(p1 + 0x10) != index) {
    return 0;
  }
  uintptr p2 = r8(p1);
  uintptr p3 = r8(p2 + 8);
  uint32 tmp_index = r1(p3);
  if ((uint8)tmp_index == 0xFF) {
    return 0;
  }
  uintptr p4 = r8(p2);
  auto obj_index = r4(p4 + tmp_index * 4);
  return r8(p1 + obj_index);
}

std::pair<uint64, uint64> Game::get_id(uint64 ptr) {
  if (ptr == 0) {
    return make_pair(0, 0);
  }
  return make_pair(r8(ptr + 0x10), r8(ptr + 0x18));
}

uint64 Game::get_gs58() { return SendMessage(window_, WM_GET_GS, NULL, NULL); }

uint64 Game::get_gs58_local() { return __readgsqword(0x58); }
